package com.pb.camera.h264;

import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.VideoView;

import com.pb.camera.R;
import com.pb.camera.utils.Logger;
import com.pb.camera.utils.TaskHelper;
import com.pb.camera.utils.TimeUtils;
import com.pb.camera.view.ProgressDialog;
import com.pb.camera.view.ScalePanel;
import com.pb.camera.work.ControlTask;
import com.pb.camera.work.ReceiveTask;
import com.tutk.IOTC.AVAPIs;
import com.tutk.IOTC.AVIOCTRLDEFs;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Observable;
import java.util.Observer;
import java.util.Stack;
import java.util.concurrent.ExecutorService;

public class ControlPlayBack implements ScalePanel.OnValueChangeListener, Observer, View.OnClickListener {
    private static final String TAG = "ControlPlayBack";
    public static final int SHOW_PROGRESS = 0;
    private static ControlPlayBack mDefault = new ControlPlayBack();
    private long zeroClockStamp;
    private VedioPlayView mVedioPlayView;
    private ScalePanel mScalePanel;
    private ImageView mIv_left_day_view;
    private ImageView mIv_right_day_view;
    private TextView mTv_goback_view_date;
    private TextView mTv_goback_view_time;
    private Calendar mCalendar;
    private boolean isLoadingEvent;
    private Context mContext;
    private Map<Calendar, List<AVIOCTRLDEFs.SAvEvent>> mCacheMap;
    private Stack<Calendar> mRequestStack; //请求栈
    private int mGobackCount; //倒退回去的天数
    private int mPlayRecordChannle = -1;
    private int mAvIndex = -1;
    private ProgressDialog mProgressDialog;
    private AVIOCTRLDEFs.SAvEvent mPlayingEvent;
    private Handler mHandler = new Handler(){

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if(msg.what == SHOW_PROGRESS){
                mProgressDialog.show();
            }
        }
    };
    public static ControlPlayBack getmDefault() {
        return mDefault;
    }

    private ControlPlayBack() {
        init();
    }

    private void init() {
        ReceiveTask.getDefault().addObserver(this);
        mCalendar = Calendar.getInstance();
        zeroClockStamp = TimeUtils.getZeroClockStamp(mCalendar) * 1000;
        mCacheMap = new LinkedHashMap<>();
        mRequestStack = new Stack<>();
        requestEvent();
    }

    @Override
    public void onValueChange(float value) {
    }

    @Override
    public void update(Observable observable, final Object data) {
        synchronized (this) {
            if (data != null && data instanceof AVIOCTRLDEFs.SMsgAVIoctrlListEventResp) {
                //在子线程处理数据，通知过来要在主线程解析
                AVIOCTRLDEFs.SMsgAVIoctrlListEventResp eventResp = ((AVIOCTRLDEFs.SMsgAVIoctrlListEventResp) data);
                List events = mCacheMap.get(mCalendar);
                if (events != null && !events.containsAll(eventResp.stEvents)) {
                    events.removeAll(eventResp.stEvents); //两个集合的交集
                    events.addAll(eventResp.stEvents);
                } else if (events.containsAll(eventResp.stEvents) || events == null)
                    return;
                if (eventResp.endflag != 1) {
                    requestEvent();
                    return;
                }
                List<AVIOCTRLDEFs.SAvEvent> eventTimes = mCacheMap.get(mCalendar);
                long[] timesArray = new long[eventTimes.size()];
                for (int count = 0; count < eventTimes.size(); count++) {
                    AVIOCTRLDEFs.SAvEvent sAvEvent = eventTimes.get(count);
                    timesArray[count] = TimeUtils.getTimeMills(sAvEvent.utctime.hour, sAvEvent.utctime.minute, sAvEvent.utctime.second) + zeroClockStamp;
                }
                mScalePanel.setEventTimes(timesArray); //在子线程中通知scalePanle更新视图
                synchronized (mRequestStack) {
                    if (mRequestStack.size() > 0) {
                        mCalendar = mRequestStack.pop();
                        requestEvent();
                    } else {
                        isLoadingEvent = false;
                    }
                }
                mProgressDialog.dismiss();
            }
        }
        if (data != null && data instanceof AVIOCTRLDEFs.SMsgAVIoctrlPlayRecordResp
                && ((AVIOCTRLDEFs.SMsgAVIoctrlPlayRecordResp) data).command == AVIOCTRLDEFs.AVIOCTRL_RECORD_PLAY_START) {
            TaskHelper.exec(new Runnable() {
                @Override
                public void run() {
                    if (mAvIndex > 0 && mPlayRecordChannle > 0) { //录像回放通道已经打开，不需要再次去打开
                        mProgressDialog.dismiss();
                        return;
                    }
                    mPlayRecordChannle = ((AVIOCTRLDEFs.SMsgAVIoctrlPlayRecordResp) data).result;
                    mAvIndex = AVAPIs.avClientStart(0, "admin", "888888", 20000, null, mPlayRecordChannle);
                    if (mAvIndex > 0) {
                        Logger.e(TAG, "start client success!");
                        int ret = AVAPIs.avSendIOCtrl(mPlayRecordChannle, AVIOCTRLDEFs.IOTYPE_USER_IPCAM_START,
                                new byte[8], 8);
                        if (ret < 0)
                            Logger.e(TAG, "start record video stream fialed");
                        Logger.d(TAG, "start record video stream success");
                        ret = AVAPIs.avSendIOCtrl(mPlayRecordChannle, AVIOCTRLDEFs.IOTYPE_USER_IPCAM_AUDIOSTART,
                                new byte[8], 8);
                        if (ret < 0)
                            Logger.e(TAG, "start record audio stream fialed");
                        Logger.e(TAG, "start record audio stream success");
                        VideoBufferThread videoBufferThread = mVedioPlayView.getmVideoBufferThread();
                        mVedioPlayView.getmAudioBufferThread().setAvIndex(mAvIndex);
                        videoBufferThread.setAvIndex(mAvIndex);
                    } else
                        Logger.e(TAG, "start client failed!");
                    mProgressDialog.dismiss();
                }
            });
        }
    }

    @Override
    public void onValueChangeEnd(Calendar calendar) {
        if (calendar.get(Calendar.DAY_OF_MONTH) != mCalendar.get(Calendar.DAY_OF_MONTH)) {
            requestEvent();
            mCalendar = calendar;
        } else {
            List<AVIOCTRLDEFs.SAvEvent> events = mCacheMap.get(mCalendar);
            AVIOCTRLDEFs.SAvEvent closestEvent;
            if (events != null && events.size() > 0) {
                closestEvent = events.get(0);
                int minimumDiff = TimeUtils.calculateTimeDiff(calendar, closestEvent);
                Logger.d(TAG, calendar.toString());
                for (AVIOCTRLDEFs.SAvEvent event : events) {
                    int timeDiff = TimeUtils.calculateTimeDiff(calendar, event);
                    Logger.d(TAG, event.utctime.toString() + " " + timeDiff);
                    if (minimumDiff > timeDiff) {
                        minimumDiff = timeDiff;
                        closestEvent = event;
                    }
                }
                calendar.set(Calendar.HOUR_OF_DAY, closestEvent.utctime.hour + 8);
                calendar.set(Calendar.MINUTE, closestEvent.utctime.minute);
                calendar.set(Calendar.SECOND, closestEvent.utctime.second);
                if (mProgressDialog != null)
                    mProgressDialog.show();
                playEvent(closestEvent);
                mScalePanel.setCalendar(calendar);
            }
        }
    }

    private void playEvent(final AVIOCTRLDEFs.SAvEvent closestEvent) {
        TaskHelper.exec(new Runnable() {
            @Override
            public void run() {
                if (mAvIndex > 0 && mPlayRecordChannle > 0 && mPlayingEvent != null){
                    ControlTask.playRecord(0, AVIOCTRLDEFs.AVIOCTRL_RECORD_PLAY_STOP, 0, mPlayingEvent);
                    stopPlayRecord();
                }

                ControlTask.playRecord(0, AVIOCTRLDEFs.AVIOCTRL_RECORD_PLAY_START, 0, closestEvent);
                mPlayingEvent = closestEvent;
            }
        });
    }

    public void init(Context context, VedioPlayView vedioPlayView,
                     ScalePanel scalePanel, ImageView iv_left_day_view,
                     ImageView iv_right_day_view, TextView tv_goback_view_date,
                     TextView tv_goback_view_time) {
        this.mVedioPlayView = vedioPlayView;
        this.mContext = context;
        this.mScalePanel = scalePanel;
        mScalePanel.setValueChangeListener(this);
        this.mIv_left_day_view = iv_left_day_view;
        this.mIv_right_day_view = iv_right_day_view;
        this.mTv_goback_view_date = tv_goback_view_date;
        mIv_right_day_view.setOnClickListener(this);
        mIv_left_day_view.setOnClickListener(this);
        mIv_right_day_view.setVisibility(View.INVISIBLE);
        mProgressDialog = new ProgressDialog(mContext, false);
        this.mTv_goback_view_time = tv_goback_view_time;
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.iv_left_day_view: {
                Calendar calendar = changeTimePanle(-1);
                mGobackCount += 1;
                if (mGobackCount == 1)
                    mIv_right_day_view.setVisibility(View.VISIBLE);
                if (isLoadingEvent) {
                    addToRequestStack(calendar);
                    return;
                }
                mCalendar = calendar;
                requestEvent();
                isLoadingEvent = true;
            }
            break;
            case R.id.iv_right_day_view: {
                if (mGobackCount == 0)
                    return;
                Calendar calendar = changeTimePanle(1);
                if (mGobackCount == 1)
                    mIv_right_day_view.setVisibility(View.INVISIBLE);
                mGobackCount -= 1;
                if (isLoadingEvent) {
                    addToRequestStack(calendar);
                    return;
                }
                mCalendar = calendar;
                requestEvent();
                isLoadingEvent = true;
            }
            break;
        }
    }

    private void addToRequestStack(Calendar calendar) {
        synchronized (calendar) {
            mRequestStack.removeAllElements(); //清除掉所有栈内未进行请求的calendar
            mRequestStack.push(calendar);
        }
    }

    private Calendar changeTimePanle(int appendDay) {
        Calendar calendar = (Calendar) mScalePanel.getCalendar().clone();
        calendar.set(Calendar.DAY_OF_MONTH, calendar.get(Calendar.DAY_OF_MONTH) + appendDay);
        mScalePanel.setCalendar(calendar);
        return calendar;
    }

    //如果是新的日期并且cacheMap里面已经有缓存那么就不需要再次去请求了
    public void requestEvent() {
        mHandler.sendEmptyMessage(SHOW_PROGRESS);
        zeroClockStamp = TimeUtils.getZeroClockStamp(mCalendar) * 1000;
        if (mCacheMap.get(mCalendar) == null) {
            List<AVIOCTRLDEFs.SAvEvent> sAvEvents = new ArrayList<AVIOCTRLDEFs.SAvEvent>();
            mCacheMap.put(mCalendar, sAvEvents);
        }
        TaskHelper.exec(new Runnable() {
            @Override
            public void run() {
                ControlTask.getListEvent(0, zeroClockStamp,
                        mCalendar.getTimeInMillis() - 8 * 3600 * 1000, (byte) AVIOCTRLDEFs.AVIOCTRL_EVENT_MOTIONDECT, (byte) 0);
            }
        });
    }

    public void stopPlayRecord() {
        TaskHelper.exec(new Runnable() {
            @Override
            public void run() {
                if (mAvIndex != -1) {
                    AVAPIs.avSendIOCtrl(mAvIndex, AVIOCTRLDEFs.IOTYPE_USER_IPCAM_STOP,
                            new byte[8], 8);
                    AVAPIs.avClientStop(mAvIndex);
                }
                if (mPlayRecordChannle != -1)
                    AVAPIs.avClientExit(0, mPlayRecordChannle);
                mAvIndex = -1;
                mPlayRecordChannle = -1;
            }
        });
    }
}
